package Options::OrderSync::API::OrderUpdate;

use strict;
use warnings;
use DE_EPAGES::Core::API::Error qw (Error );
use DE_EPAGES::Trigger::API::Trigger qw ( TriggerHook );
use DE_EPAGES::Core::API::Log qw (LogDebug GetLog);
use DE_EPAGES::Object::API::Factory
    qw( LoadObject ExistsObjectByPath LoadObjectByPath Transaction DeleteObject LoadClassByAlias);
use DE_EPAGES::Order::API::LineItemContainer qw(SaveShipping);
use DE_EPAGES::Object::API::Object::Object qw(clone insertChild);
use Data::Dumper;
use Options::Attributes::API::InterfaceValidateWebOrder;
use Options::UserSync::API::CountriesConverter;
use Options::OrderSync::API::ExtractOrderDetails;

sub ValidateWebOrder {
    my ($hParams)         = @_;
    my $CountryConverter  = new Options::UserSync::API::CountriesConverter();
    my $LineItemContainer = $hParams->{Object};

    if ( $LineItemContainer->get('RelativePath') =~ m/AnonymousUsers/ ) {
        GetLog->debug("This is AnonymousUsers - basket validation skiped!");
        return;
    }
    else {

        my $LineItemProductUpdate
            = $LineItemContainer->childrenByClass('LineItemProductUpdate');
        my $lineItems = $LineItemContainer->get('LineItems');

        zeroLineItemsOptionsPrice($lineItems);

        deleteOptionsBonusLineItem($lineItems);
        my $LineItemProducts
            = $LineItemContainer->childrenByClass('LineItemProduct');

        if ( ( scalar @$LineItemProducts ) > 0 ) {

            my $orderToValidate
                = &Options::OrderSync::API::ExtractOrderDetails::getCreditCardDetails
                ($LineItemContainer);

            my $Basket = $LineItemContainer->get('Parent');

            my ( $itemsArray, $BasketLineItemsCounter )
                = &Options::OrderSync::API::ExtractOrderDetails::addLineItemsToValidateRequest
                ($LineItemContainer);

            $orderToValidate->{'OrderLine'} = $itemsArray;

            my $Customer = $Basket->get('Customer');

            my $OptionsCustNumber = $Customer->get('OptionsCustId');
            if (  !$OptionsCustNumber
                || $OptionsCustNumber eq ""
                || !defined($OptionsCustNumber) )
            {
                $OptionsCustNumber = 0;
            }

            my $ShopperID = $Customer->get('OptionsShopperID');

            $orderToValidate->{'CardAmount'} = 0;
            $orderToValidate->{'CountryCode'}
                = $LineItemContainer->get('BillingCountryID');
            $orderToValidate->{'CustomerNumber'} = $OptionsCustNumber;
            $orderToValidate->{'ShopperID'}      = $ShopperID;
            $orderToValidate->{'Currency'}
                = $LineItemContainer->get('CurrencyID');
            $orderToValidate->{'CustomerType'}  = 7;
            $orderToValidate->{'OrderDate'}     = '';
            $orderToValidate->{'OrderNumber'}   = '';
            $orderToValidate->{'SourceKey'}     = 'WEB1BIB';
            $orderToValidate->{'DeliverDate'}   = '2010-12-19T00:00:00';
            $orderToValidate->{'Discount'}      = 0;
            $orderToValidate->{'ShippingCost'}  = 0;
            $orderToValidate->{'OrderDate'}     = '2010-12-14T00:00:00';
            $orderToValidate->{'VoucherAmount'} = 0;
            $orderToValidate->{'ChequeAmount'}  = 0;
            $orderToValidate->{'Reprice'}       = 'true';
            $orderToValidate->{'CashAmount'}    = 0;
            $orderToValidate->{'CreditAmount'}  = 0;

            GetLog->debug(
                "TEST: UIBasket2Order: " . Dumper($orderToValidate) );

            my $WSLinkUpdate
                = Options::Attributes::API::InterfaceValidateWebOrder::new(
                "Options::Attributes::API::InterfaceValidateWebOrder",
                "ValidateWebOrder",
                "ValidateWebOrderRequest",
                $orderToValidate,
                ""
                );

            my $Result = $WSLinkUpdate->hitMe();

            # eq undef
            if ( !$Result ) {
                GetLog->debug(
                    "!!!!!!!  ERROR NO RESPONSE FROM OPTIONS BIBLIOPHILE  !!!!!!"
                );
            }

            #Count how many lineitems we get from options
            my $LineItemOptions;
            my $LineItem;

             #Make always array regardless how many items returned
            convertItemsAlwaysToArray($Result);

            GetLog->debug(
                "TEST: UIBasket2Order RESULT: " . Dumper($Result) );
            my $ResponseLineItemsCounter
                = countResponseLineItemsCounter($Result);

            # IF WE HAVE MORE LINE ITEMS IN RETURN
            my $bonusProductCodes = returnBonusProduct($Result);

            # Convert array to hash with number => quantity
            # to avoid dbi error
            my $bonusHash = returnBonusProductHash($bonusProductCodes);

            GetLog->debug( "bonus bonusHash: " . Dumper($bonusHash) );

            foreach my $key ( keys %$bonusHash ) {

                #TO DO: dOUBLE CHECK IF object exists
                my $NewProduct = LoadObjectByPath(
                    "/Shops/Bibliophile/Products/" . $key );
                my $NewProductPrice
                    = $NewProduct->get('ListPrices')->[0]->{'ListPrice'};
                my $NewLineItemPrice = $NewProductPrice * $bonusHash->{$key};
                GetLog->debug( "bonus product price: "
                        . $NewProduct->get('ListPrices')->[0]
                        ->{'ListPrice'} );
                my $LineItemNew = $LineItemContainer->insertLineItem(
                    LoadClassByAlias('LineItemProduct'),
                    {   'Quantity'                 => $bonusHash->{$key},
                        'Product'                  => $NewProduct,
                        'LineItemPrice'            => $NewLineItemPrice,
                        'IsLineItemOptionsBonus'   => 1,
                        'LineItemPriceFromOptions' => 0
                    }
                );
            }

            GetLog->debug(
                "bonus bonusProductCodes: " . Dumper($bonusProductCodes) );

            $Basket->set(
                {   'TotalDiscountFromOptions' =>
                        $Result->{OrderHeader}->{Discount}
                }
            );

            GetLog->debug(
                "ADDED DISCOUNT: " . $Result->{OrderHeader}->{Discount} );

     # save new prices to LineItemPriceFromOptions attribute for each lineitem
            foreach my $LineItem (@$lineItems) {
                if ( $LineItem->get('Class')->get('Alias') ne
                    "LineItemProductUpdate" )
                {
                    foreach $LineItemOptions (
                        @{ $Result->{OrderLines}->{NewSalesOrderLine} } )
                    {
                        if ( $LineItem->get('SKU') eq
                            $LineItemOptions->{ProductCode} )
                        {
                            my $price
                                = $LineItem->get('LineItemPriceFromOptions');
                            $price = $price + $LineItemOptions->{LineValue};
                            $LineItem->set(
                                { 'LineItemPriceFromOptions' => $price } );

                        }
                    }
                }
            }
        }
        return;
    }
}

sub returnBonusProductHash {
    my ($productArray) = @_;
    my %prodHash;
    foreach (@$productArray) {
        if ( exists $prodHash{$_} ) {
            my $counter = $prodHash{$_};
            $counter++;
            $prodHash{$_} = $counter;
        }
        else {
            $prodHash{$_} = 1;
        }
    }
    return \%prodHash;
}

sub returnBonusProduct {
    my ($Result) = @_;
    my @specialBonus;
    if ( ref($Result) eq "HASH" ) {
        if ( ref( $Result->{OrderSpecialOffers} ) eq "HASH" ) {
            if (ref( $Result->{OrderSpecialOffers}->{OrderSpecialOffer} ) eq
                "HASH" )
            {
                if (defined(
                        $Result->{OrderSpecialOffers}->{OrderSpecialOffer}
                            ->{OfferProducts}->{OfferProduct}->{ProductCode}
                    )
                    )
                {
                    push( @specialBonus,
                        $Result->{OrderSpecialOffers}->{OrderSpecialOffer}
                            ->{OfferProducts}->{OfferProduct}
                            ->{ProductCode} );
                    return \@specialBonus;
                }
                else {
                    return \@specialBonus;
                }
            }
            elsif (
                ref( $Result->{OrderSpecialOffers}->{OrderSpecialOffer} ) eq
                "ARRAY" )
            {
                foreach (
                    @{ $Result->{OrderSpecialOffers}->{OrderSpecialOffer} } )
                {
                    push( @specialBonus,
                        $_->{OfferProducts}->{OfferProduct}->{ProductCode} );
                }
                return \@specialBonus;
            }
        }
    }
    return \@specialBonus;
}

sub countResponseLineItemsCounter {
    my ($Result) = @_;
    my $ResponseLineItemsCounter = 0;
    foreach my $LineItemOptions (
        @{ $Result->{OrderLines}->{NewSalesOrderLine} } )
    {
        $ResponseLineItemsCounter++;
    }
    return $ResponseLineItemsCounter;
}

sub convertItemsAlwaysToArray {
    my ($Result) = @_;
    if ( ref( $Result->{OrderLines}->{NewSalesOrderLine} ) eq "HASH" ) {
        my $onelineitem = $Result->{OrderLines}->{NewSalesOrderLine};
        delete $Result->{OrderLines}->{NewSalesOrderLine};
        push( @{ $Result->{OrderLines}->{NewSalesOrderLine} }, $onelineitem );
    }
    return;
}

sub zeroLineItemsOptionsPrice {
    my ($lineItems) = @_;
    foreach my $LineItem (@$lineItems) {
        if ($LineItem->get('Class')->get('Alias') ne "LineItemProductUpdate" )
        {
            $LineItem->set( { 'LineItemPriceFromOptions' => 0 } );
        }
    }
    return;
}

sub deleteOptionsBonusLineItem {
    my ($lineItems) = @_;
    foreach (@$lineItems) {
        if ( $_->get('Class')->get('Alias') ne "LineItemProductUpdate" ) {
            if ( $_->get('IsLineItemOptionsBonus') ) {
                $_->delete;
            }
        }
    }
    return;
}

sub deleteProduct {
    my ( $productsToAdd, $product, $quantity ) = @_;
    if ( defined( $productsToAdd->{$product} ) ) {
        $productsToAdd->{$product} = $productsToAdd->{$product} - $quantity;
        if ( $productsToAdd->{$product} == 0 ) {
            delete( $productsToAdd->{$product} );
        }
    }
    return $productsToAdd;
}

sub saveProduct {
    my ( $productsToAdd, $product, $quantity ) = @_;
    if ( defined( $productsToAdd->{$product} ) ) {
        $productsToAdd->{$product} = $productsToAdd->{$product} + $quantity;
    }
    else {
        $productsToAdd->{$product} = $quantity;
    }
    return $productsToAdd;
}

1;
